/**
 * 
 */
package br.org.bertol.mestrado.engine;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.log4j.Logger;

import br.org.bertol.mestrado.engine.exception.HeuristicsException;
import br.org.bertol.mestrado.engine.fitness.ClassInstantiation;
import br.org.bertol.mestrado.engine.optimisation.aco.AntColonyOptimization;
import br.org.bertol.mestrado.engine.optimisation.entity.Ant;

/**
 * @author contaqualquer
 */
public class EngineAnt extends AbstractSearchEngine {

    /***/
    private final transient float                       threshold;

    /***/
    private final transient List<AntColonyOptimization> resultAnt;

    /***/
    private final transient float                       fEvaporation;

    /***/
    private final transient float                       fMinPheromone;

    /***/
    private final transient float                       fAlpha;

    /***/
    private final transient float                       fBeta;

    /**
     * @param startS
     *            Semáforo de start
     * @param stopS
     *            Semáforo de parada
     * @param numEval
     *            Total de iterações
     * @param objectives
     *            Lista de objetivos
     * @param storeP
     *            Caminho onde salvar os resultados detalhados
     * @param sID
     *            Identificação dp método de busca
     */
    public EngineAnt(final CountDownLatch startS, final CountDownLatch stopS,
        final int numEval, final Objective[] objectives, final String storeP,
        final String sID, final float wellThreshoold,
        final float evaporation, final float minPheromone,
        final float alpha, final float beta) {

        super(startS, stopS, numEval, objectives, storeP, sID);

        threshold = wellThreshoold;

        fEvaporation = evaporation;

        fMinPheromone = minPheromone;

        fAlpha = alpha;

        fBeta = beta;

        resultAnt = new ArrayList<AntColonyOptimization>();

    }

    /**
     * {@inheritDoc}
     * @see AbstractSearchEngine#writeToFile(PrintWriter)
     */
    @Override
    public final void writeToFile(final PrintWriter outFile) {
        outFile.println(getName());

        for (AntColonyOptimization antColonyOptimization : resultAnt) {

            if (verify.getObjectives().length == 1) {

                final Iterator<Ant> iterator = antColonyOptimization
                        .getSwarm().iterator();

                outFile.println(iterator.next().toString());
            } else {

                for (final Ant ant : antColonyOptimization
                        .getParetoBorder()) {
                    outFile.println(ant.toString());
                }
            }
        }

    }

    @Override
    public final void run() {
        try {
            // deixa sistema ponto para entrar em ação
            startSystem.await();

            if (verify.isSystemEnable()) {
                // aramazena resultado do pso em arquivo
                final PrintWriter outFile = new PrintWriter(new BufferedWriter(
                        new FileWriter(storePath + "/" + systemID
                        + "/resultado_avaliacao_" + systemID + "_ACO.txt",
                        true)));

                Logger.getLogger(this.getClass()).info("Start");

                outFile
                        .println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");

                final List<Ant> ants = new ArrayList<Ant>();

                // cria lista de ants
                for (int i = 0; i < verify.getClasses().size() / 2; i++) {
                    ants.add(new Ant(fAlpha, fBeta,
                            threshold, new ClassInstantiation(verify
                            .getStrongConstraint()), verify.getObjectives()));
                }

                // cria colônia de formigas
                final AntColonyOptimization colonyOptimization = new AntColonyOptimization(
                        verify, numIteracoes, ants, fEvaporation,
                        fMinPheromone);

                final long iniTime = System.currentTimeMillis();

                colonyOptimization.evaluate();

                resultAnt.add(colonyOptimization);

                outFile.println(getName());

                for (Ant ant : colonyOptimization.getParetoBorder()) {
                    outFile.println("| " + ant.toString() + " |");
                }

                outFile
                        .println("Processamento encerrado. Tempo total: "
                                + (float) ((System.currentTimeMillis() - iniTime) / 1000)
                                + " segundos.");

                outFile.flush();

                outFile.close();

                Logger.getLogger(this.getClass()).info("End");
            }
        } catch (InterruptedException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        } catch (IOException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        } catch (HeuristicsException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        }

        // notifica main thread
        stopSystem.countDown();
    }
}
